Skip to content

fix missing json output for theme info command when dev and theme flags are missing#6905

Open
FKauwe wants to merge 1 commit intomainfrom
fix-missing-json-output-for-theme-info
Open

fix missing json output for theme info command when dev and theme flags are missing#6905
FKauwe wants to merge 1 commit intomainfrom
fix-missing-json-output-for-theme-info

Conversation

@FKauwe
Copy link
Contributor

@FKauwe FKauwe commented Feb 27, 2026

WHY are these changes introduced?

Fixes #1064 : Theme info not outputting json with the --json flag

I identified that when running shopify theme info --json without a --theme or --development flag, execution goes to the else branch, which had no JSON handling. The JSON.stringify logic only existed in the if branch (which requires --theme or --development)

The else branch had no --json handling at all, so the flag was silently ignored.

WHAT is this pull request doing?

I could have chosen to jsonify the existing info message, but this was formulated for the tabular data to output the formatted box in the terminal and looks messy and is more difficult to parse. It would have looked like this:

Click to expand

Output:

[
  {
    "title": "Theme Configuration PROOF OF WHERE I AM",
    "body": {
      "tabularData": [
        [
          "Store",
          "f9e81e-af.myshopify.com"
        ],
        [
          "Development Theme ID",
          {
            "subdued": "Not set"
          }
        ]
      ],
      "firstColumnSubdued": true
    }
  },
  {
    "title": "Tooling and System",
    "body": {
      "tabularData": [
        [
          "Shopify CLI",
          "3.91.0"
        ],
        [
          "OS",
          "darwin-arm64"
        ],
        [
          "Shell",
          "/bin/zsh"
        ],
        [
          "Node version",
          "v23.6.1"
        ]
      ],
      "firstColumnSubdued": true
    }
  }
]

I chose to make a new, more easily parse-able json object (following the pattern of the if branch, where a clean object is also created specifically to be consumed by JSON.stringify). I built a new Interface and function to populate the object in packages/theme/src/cli/services/info.ts, then consumed it in the else branch in packages/theme/src/cli/commands/theme/info.ts

I wrote a new unittest to verify that the JSON conversion is working correctly.
All existing tests pass.

How to test your changes?

while on main, run shopify theme info --json, should see no json and formulated tabular info like this:

Screenshot 2026-02-27 at 10 17 05 AM

then pull down my branch locally,
p build ,
run shopify-dev theme info --json
see the nice JSON formatting!
Screenshot 2026-02-27 at 9 32 06 AM

Measuring impact

How do we know this change was effective? Please choose one:

  • n/a - this doesn't need measurement, e.g. a linting rule or a bug-fix

@FKauwe FKauwe requested a review from EvilGenius13 February 27, 2026 18:22
@FKauwe FKauwe self-assigned this Feb 27, 2026
@FKauwe FKauwe requested review from a team as code owners February 27, 2026 18:22
@binks-code-reviewer
Copy link

binks-code-reviewer bot commented Feb 27, 2026

🤖 Code Review · #projects-dev-ai for questions
React with 👍/👎 or reply — all feedback helps improve the agent.

Complete - No issues

📋 History

✅ 1 findings → ✅ No issues

@FKauwe FKauwe force-pushed the fix-missing-json-output-for-theme-info branch from 070e0fa to d198b78 Compare February 27, 2026 22:49
@binks-code-reviewer
Copy link

⚠️ Findings outside the diff

These findings are in files not modified by this PR and cannot be posted as inline comments.


packages/theme/src/cli/commands/theme/info.ts:38Duplicate timing event recorded (double recordTiming)

recordTiming('theme-command:info') is called at the start of command() and again at the end. With the new early return in the else branch (flags.json), behavior becomes inconsistent:

  • JSON path: timing recorded only once (line 38), because you return early.
  • Non-JSON path: timing recorded twice (line 38 and line 58).
    This can skew analytics, dashboards, and latency tracking, potentially making it look like the command ran twice or distorting timing distribution for this command.

json?: boolean
}

interface DevInfo {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we rename this to ThemeEnvironmentInfo?

Copy link
Contributor Author

@FKauwe FKauwe Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

absolutely. I chose devInfo bc there was an existing function that gathers the same/ similar info called

export async function fetchDevInfo(config: {cliVersion: string}): Promise<AlertCustomSection[]> {
  return [devConfigSection(), await systemInfoSection(config)]
}

function devConfigSection(): AlertCustomSection {
  const store = getThemeStore() ?? 'Not configured'
  const developmentTheme = getDevelopmentTheme()

  recordEvent(`theme-command:info:dev-theme-loaded:${developmentTheme}`)

  return tabularSection('Theme Configuration', [
    ['Store', store],
    ['Development Theme ID', developmentTheme ? `#${developmentTheme}` : {subdued: 'Not set'}],
  ])
}

But I agree, ThemeEnvironmentInfo is more descriptive

Copy link
Contributor Author

@FKauwe FKauwe Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and since I'm changing the Interface name I'm going to change the function that returns this type to match as well, to: themeEnvironmentInfoJSON

const store = getThemeStore()
return {
store: store ?? 'Not configured',
development_theme_id: store ? getDevelopmentTheme() ?? null : null,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This took me a minute to understand. If you don't want to make it more verbose can we wrap the first part in () so like development_theme_id: store ? (getDevelopmentTheme() ?? null) : null, ? That way you can more easily ready that it's getDevelopmentTheme that may return null OR that if store isn't found we don't want to run that method and skip right to null as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the linter unfortunately strips the ( ) as unnecessary. I will use a multi line conditional, I also agree it is difficult to read

renderInfo(formattedInfo)
} else {
const infoMessage = await fetchDevInfo({cliVersion: this.config.version})
if (flags.json) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we're calling flags.json twice now. Can you look into merging that logic?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What did you have in mind? I'm not sure I'm following.
The branching is:
if dev or theme flag present, proceed to json flag check, if present, return one converted result
OR if dev and theme flags are not present, proceed to json flag check, if present, return a *different converted result
because the initial check for theme and dev flags means there will be different data to jsonify based on that check, I don't think I can combine the json checks at a higher level further up the chain (if that's what you meant)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes that makes sense. It does do two different things so we can't really unify it.

On another note, can you move the new if (flags.json) one level up above const infoMessage = await fetchDevInfo({cliVersion: this.config.version})?

Right now what happens is that line gets run if we hit the else branch, and then if json is enabled we do nothing with that code. We should check if it's going to be json first and if not, run the const infoMessage...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants